/*
 *  ---------
 * |.##> <##.|  Open Smart Card Development Platform (www.openscdp.org)
 * |#       #|  
 * |#       #|  Copyright (c) 1999-2006 CardContact Software & System Consulting
 * |'##> <##'|  Andreas Schwier, 32429 Minden, Germany (www.cardcontact.de)
 *  --------- 
 *
 *  This file is part of OpenSCDP.
 *
 *  OpenSCDP is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  OpenSCDP is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with OpenSCDP; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

package com.jl.process.util;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.FunctionObject;
import org.mozilla.javascript.JavaScriptException;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.WrappedException;
import org.mozilla.javascript.annotations.JSConstructor;
import org.mozilla.javascript.annotations.JSFunction;

/**
 * Implements GPError native object
 * 
 * @author Andreas Schwier (info@cardcontact.de)
 */
public class GPError extends ScriptableObject {

    public final static int ACCESS_DENIED = 1;
    public final static int ARGUMENTS_MISSING = 2;
    public final static int CARD_COMM_ERROR = 3;
    public final static int CARD_INVALID_SW = 4;
    public final static int CRYPTO_FAILED = 5;
    public final static int DATA_TOO_LARGE = 6;
    public final static int DEVICE_ERROR = 7;
    public final static int INVALID_ARGUMENTS = 8;
    public final static int INVALID_DATA = 9;
    public final static int INVALID_ENCODING = 10;
    public final static int INVALID_INDEX = 11;
    public final static int INVALID_KEY = 12;
    public final static int INVALID_LENGTH = 13;
    public final static int INVALID_MECH = 14;
    public final static int INVALID_TAG = 15;
    public final static int INVALID_TYPE = 16;
    public final static int INVALID_USAGE = 17;
    public final static int KEY_NOT_FOUND = 18;
    public final static int OBJECTCREATIONFAILED = 19;
    public final static int SECURE_CHANNEL_WRONG_STATE = 20;
    public final static int TAG_ALREADY_EXISTS = 21;
    public final static int TAG_NOT_FOUND = 22;
    public final static int UNDEFINED = 23;
    public final static int UNSUPPORTED = 24;
    public final static int USER_DEFINED = 25;
    public final static int OBJECT_NOT_FOUND = 26;
    public final static int LAST_ERROR = 26;
    
    public final static String[] ErrorName = {
            "ACCESS_DENIED",
            "ARGUMENTS_MISSING",
            "CARD_COMM_ERROR",
            "CARD_INVALID_SW",
            "CRYPTO_FAILED",
            "DATA_TOO_LARGE",
            "DEVICE_ERROR",
            "INVALID_ARGUMENTS",
            "INVALID_DATA",
            "INVALID_ENCODING",
            "INVALID_INDEX",
            "INVALID_KEY",
            "INVALID_LENGTH",
            "INVALID_MECH",
            "INVALID_TAG",
            "INVALID_TYPE",
            "INVALID_USAGE",
            "KEY_NOT_FOUND",
            "OBJECTCREATIONFAILED",
            "SECURE_CHANNEL_WRONG_STATE",
            "TAG_ALREADY_EXISTS",
            "TAG_NOT_FOUND",
            "UNDEFINED",
            "UNSUPPORTED",
            "USER_DEFINED",
            "OBJECT_NOT_FOUND"
    };
    

    
    /**
     * Empty constructor calling super()
     *
     */
    public GPError() {
        super();
    }



    /**
     * @see org.mozilla.javascript.ScriptableObject#getClassName()
     */
    @Override
	public String getClassName() {
        return "GPError";
    }



    /**
     * Throw a ScriptRuntime error wrapping a GPError object
     * 
     * @param obj Object used to obtain the top-level scope
     * @param className Class name throwing the exception
     * @param error
     * @param reason
     * @param message
     * @return RuntimeException, however this function will never return, as it calls Context.throwAsScriptRuntimeEx().
     */
    public static RuntimeException throwAsGPErrorEx(Scriptable obj, String className, int error, int reason, String message) {
        // Create GPError object
        Object[] _args = { className, new Integer(error), new Integer(reason), message};
        Context cx = Context.getCurrentContext();
        Scriptable gperr = cx.newObject(ScriptableObject.getTopLevelScope(obj), "GPError", _args);

        // Create exception and use WrappedException constructor to determin current
        // source name and line number. Yes, it's a little bit strange, but seems to be
        // the only way

        JavaScriptException jse = new JavaScriptException(gperr, null, -1);
        WrappedException we = new WrappedException(jse);
        int lineNumber = we.lineNumber();
        if (lineNumber > 0) {
        	jse.initLineNumber(lineNumber);
        }
        jse.initSourceName(we.sourceName());
        throw jse;
//        return Context.throwAsScriptRuntimeEx(new JavaScriptException(gperr, className, 1));
    }
    
    
    
    /**
     * Throw a ScriptRuntime error wrapping a GPError object
     * 
     * @param obj Scriptable object that throws the exception
     * @param error Error code
     * @param reason Error reason
     * @param message Error message
     * @return RuntimeException, however this function will never return, as it calls Context.throwAsScriptRuntimeEx().
     */
    public static RuntimeException throwAsGPErrorEx(Scriptable obj, int error, int reason, String message) {
        return GPError.throwAsGPErrorEx(obj, obj.getClassName(), error, reason, message);
    }
    
    
    
    /**
     * The constructor method for the GPError object can be used to construct a GPError object
     * 
     * ECMA constructor: 
     * GPError new GPError(String className, Number error, Number reason, String message)
     * 
     * @param className Class name that caused the error
     * @param error The error parameter corresponds to the constant values defined for the GPError object.
     * @param reason Reason code for error
     * @param message Message describing the error
     * 
     */
    @JSConstructor
    public void jsConstructor(String className, int error, int reason, String message) {
        put("className", this, className);
        put("error", this, new Integer(error));
        put("reason", this, new Integer(reason));
        put("message", this, message);
        put("name", this, "GPError");
        WrappedException we = new WrappedException(new Exception());
        put("fileName", this, we.sourceName());
        put("lineNumber", this, we.lineNumber());
    }
    
    
    
    /**
     * Set additional properties in prototype object
     * 
     * Called from runtime in defineClass() method
     * 
     * @param scope Scope in which class is defined
     * @param ctor Constructor function object
     * @param proto Prototype function object
     */
    public static void finishInit(Scriptable scope, FunctionObject ctor, Scriptable proto) {
        
        for (int i = 1 ; i <= LAST_ERROR; i++) {
            ScriptableObject.defineProperty(ctor, ErrorName[ i - 1], new Integer(i), 0);
        }
    }
  
    /**
     * Return object content as string
     * @return String
     */
    @Override
	@JSFunction
    public String toString() {

        String errtxt;
        String className = Context.toString(get("className", this));
        int error = (int)Context.toNumber(get("error", this));
        int reason = (int)Context.toNumber(get("reason", this));
        String message = Context.toString(get("message", this));
        String fileName = Context.toString(get("fileName", this));
        int lineNumber = (int)Context.toNumber(get("lineNumber", this));
        
        if ((error >= 1) && (error <= LAST_ERROR))
            errtxt = ErrorName[error - 1];
        else
            errtxt = "" + error;
        
        return className + " (" + errtxt + "/" + reason + ") - \"" + message + "\" in " + fileName + "#" + lineNumber;
    }
    
    
    
    /**
     * Throw exception for testing
     * 
     * @param error
     * @param reason
     * @param Message
     */
    @JSFunction
    public void selfTest(int error, int reason, String Message) {
        GPError.throwAsGPErrorEx(this, error, reason, Message);
    }
}
